package edu.ccut.saturn.component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 工作流组件管理者，提供了单态实例维护加载的工作流组件信息，并提供了获得工作流组件配置文件的字节数组的方法。
 * <p><li>字段bundleValidateInfos：记录了每个bundle中的验证组件信息；
 * <li>字段validate：记录了通过全局键值标识的验证组件的运行时实例。
 * 
 * @author 温建
 * 
 * @version 1.0 2008.9.04
 * 
 * @see IBundleWorkFlowInfo
 * 
 */
public class SaturnWorkFlowManager {

	private static final String CHAR_SET = "UTF-8";

	private static final String LOGGER_KEY_BUNDLE_SERVICE = SaturnLoggerManager.LOGGER_KEY_BUNDLE_SERVICE;

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(LOGGER_KEY_BUNDLE_SERVICE);

	private static final String KEY_SEPARATOR = "::";

	private Map<String, IBundleWorkFlowInfo> bundleWorkFlowInfos;

	private Map<String, URL> workFlowUrls;

	private static SaturnWorkFlowManager instance;

	static {
		instance = new SaturnWorkFlowManager();
	}

	private SaturnWorkFlowManager() {
		this.bundleWorkFlowInfos = new HashMap<String, IBundleWorkFlowInfo>();
		this.workFlowUrls = new HashMap<String, URL>();
	}

	/**
	 * 获得单态实例
	 * @return
	 */
	public static SaturnWorkFlowManager getInstance() {
		return instance;
	}

	/**
	 * add BundleWorkFlowInfo to manager
	 * 
	 * @param bundleInfo
	 */
	public void addBundleWorkFlowInfo(IBundleInfo bundleInfo) {
		this.bundleWorkFlowInfos.put(bundleInfo.getBundleSymbolicName(),
				bundleInfo.getBundleWorkFlowInfo());

		logger.debug("add bundleWorkFlowInfo key \""
				+ bundleInfo.getBundleSymbolicName() + "\"");
	}

	/**
	 * remove BundleWorkFlowInfo by bundle symbolic name from manager
	 * 
	 * @param bundleSymbolicName
	 */
	public void removeBundleWorkFlowInfo(String bundleSymbolicName) {
		if (this.bundleWorkFlowInfos.containsKey(bundleSymbolicName)) {
			IBundleWorkFlowInfo bundleWorkFlowInfo = this.bundleWorkFlowInfos
					.get(bundleSymbolicName);

			for (String workFlowKey : bundleWorkFlowInfo.getWorkFlowKeys()) {
				this.removeURL(bundleSymbolicName, workFlowKey);
			}

			this.bundleWorkFlowInfos.remove(bundleSymbolicName);
			logger.debug("remove bundleWorkFlowInfo key is : \""
					+ bundleWorkFlowInfo.getBundleSymbolicName() + "\"");

			return;
		}

		logger
				.warn("failed to remove bundleWorkFlowInfo, because the bundle key : \""
						+ bundleSymbolicName + "\" is not valid");
	}

	/**
	 * Get a {@link IBundleInfo} by symbolic name
	 * 
	 * @param bundleSymbolicName
	 * @return if symbolic name is not exist, return null.
	 */
	public IBundleWorkFlowInfo getBundleWorkFlowInfo(String bundleSymbolicName) {
		return this.bundleWorkFlowInfos.get(bundleSymbolicName);
	}

	/**
	 * Get all bundle symbolic name Set
	 * 
	 * @return
	 */
	public Set<String> getBundleSymbolicNames() {
		return this.bundleWorkFlowInfos.keySet();
	}

	/**
	 * 通过工作流组件的全局键值获得工作流组件配置文件的url信息
	 * @param workFlowFullKey
	 * @return
	 * @throws SaturnComponentException
	 */
	public URL getWorkFlowURL(String workFlowFullKey)
			throws SaturnComponentException {

		int index = workFlowFullKey.indexOf(KEY_SEPARATOR);

		if (index == -1 || index == 0 || index == workFlowFullKey.length() - 2) {
			throw new SaturnComponentException(workFlowFullKey
					+ " is not a valid key");
		}
		String bundleSymbolicName = workFlowFullKey.substring(0, index);
		if (this.workFlowUrls.containsKey(workFlowFullKey)) {
			return this.workFlowUrls.get(workFlowFullKey);
		}

		IWorkFlowInfo workFlowInfo = this.getWorkFlowInfo(bundleSymbolicName,
				workFlowFullKey);

		if (workFlowInfo == null) {
			throw new SaturnComponentException(workFlowFullKey
					+ " dose not exist! ");
		}
		URL url = workFlowInfo.getWorkFlowURL();
		this.workFlowUrls.put(workFlowFullKey, url);

		return url;
	}

	/**
	 * 获得根据工作流组件的全局标识唯一指定的工作流组件中记录的byte数组信息;
	 * 通过工作流组件配置文件的URL对象获得的。
	 * @param workFlowFullKey
	 * @return
	 * @throws SaturnComponentException
	 */
	public byte[] getInputStream(String workFlowFullKey)
			throws SaturnComponentException {

		URL url = getWorkFlowURL(workFlowFullKey);
		String line = null;
		BufferedReader bufferedReader = null;
		try {
			bufferedReader = new BufferedReader(new InputStreamReader(url.openStream(), CHAR_SET));
			StringBuffer data = new StringBuffer();
			while ((line = bufferedReader.readLine()) != null) {
				data.append(line).append("\n");
			}
			return data.toString().getBytes(CHAR_SET);
		} catch (Exception e) {
			throw new SaturnComponentException(e);
		} finally {
			try {
				if (bufferedReader != null) {
					bufferedReader.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 通过bundle名称和工作流组件键值获得工作流组件信息。
	 * @param bundleSymbolicName
	 * @param workFlowFullKey
	 * @return
	 * @throws SaturnComponentException
	 */
	public IWorkFlowInfo getWorkFlowInfo(String bundleSymbolicName,
			String workFlowFullKey) throws SaturnComponentException {

		IBundleWorkFlowInfo bundleWorkFlowInfo = this.bundleWorkFlowInfos
				.get(bundleSymbolicName);
		
		if (bundleWorkFlowInfo == null) {
			throw new SaturnComponentException(
					"can't find bundle with symbolicName = ["
							+ bundleSymbolicName + "]");
		}

		IWorkFlowInfo workFlowInfo = bundleWorkFlowInfo
				.getWorkFlowInfo(workFlowFullKey);

		return workFlowInfo;
	}

	private void removeURL(String bundleSymbolicName, String workFlowFullKey) {
		if (this.workFlowUrls.containsKey(workFlowFullKey)) {
			this.workFlowUrls.remove(workFlowFullKey);
		}
		logger
				.warn("failed to remove workflowInfo, because the workflow key : \""
						+ workFlowFullKey + "\" is not valid");
	}
}
